#include "UpdateBLL.h"
#include "UpdateData.h"
#include "DeviceInfo.h"
#include <string.h>
#include "flash.h"

#include "DeviceInfoBLL.h"
#include "Tools.h"

#include <stdio.h>

static UpdatePackageInfo *pUpdatePackageInfo;

void InitUpdateInfo(void)
{
	pUpdatePackageInfo = GetUpdatePackageInfo();
	InitUpdatePackageInfo();
}

/*
*********************************************************************************************************
*	函 数 名: JumpToBootloader
*	功能说明: 跳转到系统BootLoader
*	形    参: 无
*	返 回 值: 无
*********************************************************************************************************
*/
void JumpToApplication(volatile uint32_t AppAddr)
{
	uint32_t i=0;
	void (*SysMemBootJump)(void);         /* 声明一个函数指针 */
	__IO uint32_t BootAddr = AppAddr;  		/* APP程序的Flash地址 */
	
	/* 关闭全局中断 */
	DISABLE_GLOBAL_INT(); 

	/* 关闭滴答定时器，复位到默认值 */
	SysTick->CTRL = 0;
  SysTick->LOAD = 0;
  SysTick->VAL = 0;

#if 0
	//跳转到App之前，关闭所有的外设，因为
	//App中还会重新初始化
	extern CAN_HandleTypeDef hcan1;
	HAL_CAN_MspDeInit(&hcan1);
	
	extern SPI_HandleTypeDef hspi1;
	HAL_SPI_MspDeInit(&hspi1);
	
	extern UART_HandleTypeDef huart4;
	extern UART_HandleTypeDef huart1;
	HAL_UART_MspDeInit(&huart4);
	HAL_UART_MspDeInit(&huart1);
#endif

	
	/* 设置所有时钟到默认状态，使用HSI时钟 */
	HAL_RCC_DeInit();
	
	/* 关闭所有中断，清除所有中断挂起标志 */
	for (i = 0; i < 8; i++)
	{
		NVIC->ICER[i]=0xFFFFFFFF;
		NVIC->ICPR[i]=0xFFFFFFFF;
	}	

	/* 使能全局中断 */
	ENABLE_GLOBAL_INT();

	/* 跳转到系统BootLoader，首地址是MSP，地址+4是复位中断服务程序地址 */
	SysMemBootJump = (void (*)(void)) (*((uint32_t *) (BootAddr + 4)));

	/* 设置主堆栈指针 */
	__set_MSP(*(uint32_t *)BootAddr);
	
	/* 在RTOS工程，这条语句很重要，设置为特权级模式，使用MSP指针 */
	__set_CONTROL(0);

	/* 跳转到系统BootLoader */
	SysMemBootJump();

	/* 跳转成功的话，不会执行到这里，用户可以在这里添加代码 */
	while (1)
	{

	}
}

void SetUpdatePackageInfo(uint32_t u32PackageSize)
{
	pUpdatePackageInfo->u32PackageSize = u32PackageSize;
}

uint32_t GetUpdatePackageSize(void)
{
	return pUpdatePackageInfo->u32PackageSize;
}

uint8_t* GetUpdatePackageBuff(void)
{
	return pUpdatePackageInfo->u32PackageBuff;
}

void SavePackageToFlash(uint8_t *data, uint8_t length)
{
	uint32_t pack_recv_index = 0;
	uint32_t pack_buff_cnt = pUpdatePackageInfo->u32PackageHaveReceivedSize / PACKAGE_BUFF_SIZE;
	
	if(length > 0)
	{
		memcpy((pUpdatePackageInfo->u32PackageBuff) + pUpdatePackageInfo->u32PackageBuffCnt,
			data, length);
	}
	else
	{
		return;
	}

	
	pUpdatePackageInfo->u32PackageBuffCnt += length;
	pUpdatePackageInfo->u32PackageHaveReceivedSize += length;
	
	pack_recv_index = pUpdatePackageInfo->u32PackageHaveReceivedSize % PACKAGE_BUFF_SIZE;
	if((pack_recv_index == 0 ||
			pUpdatePackageInfo->u32PackageHaveReceivedSize == pUpdatePackageInfo->u32PackageSize) && 
			pUpdatePackageInfo->u32PackageHaveReceivedSize != 0)
	{
		uint32_t write_length = 0;
		if(pack_recv_index == 0)
			write_length = PACKAGE_BUFF_SIZE  / sizeof(uint32_t);
		else
			write_length = pUpdatePackageInfo->u32PackageBuffCnt / sizeof(uint32_t) + 1;
			
//		printf("Write Data To Flash ... ...\r\n");
		STMFLASH_Write(UPDATEDATA_ADDR + pack_buff_cnt * PACKAGE_BUFF_SIZE
										,(uint32_t *)(pUpdatePackageInfo->u32PackageBuff),
										write_length);
		
		pUpdatePackageInfo->u32PackageBuffCnt = 0;
		memset(pUpdatePackageInfo->u32PackageBuff, 0, PACKAGE_BUFF_SIZE);
		if(pUpdatePackageInfo->u32PackageHaveReceivedSize == pUpdatePackageInfo->u32PackageSize)
			pUpdatePackageInfo->u32PackageHaveReceivedSize = 0;
		
	}
}

bool MoveUpdateToApplication(void)
{
	uint32_t u32FirmwareSize = 0;
	uint16_t u16FirmwareCRC = 0;
	uint16_t u16LocalPackageCRC = 0;
	uint8_t *tmpBuff = GetUpdatePackageBuff();
	
	GetFirmwareInfo(&u32FirmwareSize, &u16FirmwareCRC);
	if(u32FirmwareSize <= 0 || u32FirmwareSize >= (128 * 1024))
		return false;
	
	uint16_t package_cnt = (u32FirmwareSize / PACKAGE_BUFF_SIZE);
	uint16_t remain_cnt = (u32FirmwareSize % PACKAGE_BUFF_SIZE);
	uint8_t crcH = 0xFF, crcL = 0xFF;
	uint16_t cnt = 0;
	
	STMFLASH_EraseSecter(APPLCATION_ADDR, APPDATA_SCT_CNT);
//	STMFLASH_EraseSecter(APPLCATION_ADDR);	
	//将updatedata区的数据拷贝到application区
	for(cnt = 0; cnt < package_cnt; cnt ++)
	{
		STMFLASH_Read(UPDATEDATA_ADDR + cnt * PACKAGE_BUFF_SIZE, 
					(uint32_t *)tmpBuff,PACKAGE_BUFF_SIZE / sizeof(uint32_t));
		
		STMFLASH_Write(APPLCATION_ADDR + cnt * PACKAGE_BUFF_SIZE, 
					(uint32_t *)tmpBuff,PACKAGE_BUFF_SIZE / sizeof(uint32_t));
		
		memset(tmpBuff, 0, PACKAGE_BUFF_SIZE);
	}
	
	if(remain_cnt)
	{
		STMFLASH_Read(UPDATEDATA_ADDR + cnt * PACKAGE_BUFF_SIZE, 
					(uint32_t *)tmpBuff, remain_cnt / sizeof(uint32_t) + 1);
		
		STMFLASH_Write(APPLCATION_ADDR + cnt * PACKAGE_BUFF_SIZE, 
					(uint32_t *)tmpBuff, remain_cnt / sizeof(uint32_t) + 1);
		
		memset(tmpBuff, 0, PACKAGE_BUFF_SIZE);
	}
	
	//对Application区的数据再做一次校验
	for(cnt = 0; cnt < package_cnt; cnt ++)
	{
		STMFLASH_Read(APPLCATION_ADDR + cnt * PACKAGE_BUFF_SIZE, 
					(uint32_t *)tmpBuff,PACKAGE_BUFF_SIZE / sizeof(uint32_t));
		
		u16LocalPackageCRC = CRC16_MODBUS(tmpBuff, PACKAGE_BUFF_SIZE, crcH, crcL);
		crcH = ((u16LocalPackageCRC >> 8) & 0xFF);
		crcL = (u16LocalPackageCRC & 0xFF);
		
		memset(tmpBuff, 0, PACKAGE_BUFF_SIZE);
	}
	
	if(remain_cnt)
	{
		STMFLASH_Read(APPLCATION_ADDR + cnt * PACKAGE_BUFF_SIZE, 
					(uint32_t *)tmpBuff, remain_cnt / sizeof(uint32_t) + 1);
		
		u16LocalPackageCRC = CRC16_MODBUS(tmpBuff, remain_cnt, crcH, crcL);
		memset(tmpBuff, 0, PACKAGE_BUFF_SIZE);
	}
	
	if(u16LocalPackageCRC == u16FirmwareCRC)
		return true;
	else
		return false;
}

/**
  \brief   Set Base Priority with condition
  \details Assigns the given value to the Base Priority register only if BASEPRI masking is disabled,
           or the new value increases the BASEPRI priority level.
  \param [in]    basePri  Base Priority value to set
 */
static void set_BASEPRI_MAX(uint32_t basePri)
{
  register uint32_t __regBasePriMax      __ASM("basepri_max");
  __regBasePriMax = (basePri & 0xFFU);
}

void ResetSystem(void)
{
	set_BASEPRI_MAX(1);
	NVIC_SystemReset();
}





